home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / flash-0.4.3 / lib / graphic.cc < prev    next >
C/C++ Source or Header  |  1999-01-01  |  17KB  |  861 lines

  1. ////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998 Olivier Debon
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. // 
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //  
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <assert.h>
  27. #include <sys/ipc.h>
  28. #include <sys/shm.h>
  29. #include <X11/cursorfont.h>
  30.  
  31. static char *rcsid = "$Id: graphic.cc,v 1.9 1999/02/14 22:04:22 olivier Exp $";
  32.  
  33. #include "character.h"
  34. #include "graphic.h"
  35. #include "displaylist.h"
  36.  
  37. #include "sqrt.h"
  38.  
  39. #define PRINT 0
  40.  
  41. static char cmp8[256];    // 8bit colormap
  42.  
  43. static long
  44. allocColor15(Color color)
  45. {
  46.     return (color.red >> 3)<<10 | (color.green>>3)<<5 | (color.blue>>3);
  47. }
  48.  
  49. static long
  50. allocColor16_646(Color color)
  51. {
  52.     return (color.red >> 2)<<10 | (color.green>>4)<<6 | (color.blue>>2);
  53. }
  54.  
  55. static long
  56. allocColor16_565(Color color)
  57. {
  58.     return (color.red >> 3)<<11 | (color.green>>2)<<5 | (color.blue>>3);
  59. }
  60.  
  61. static long
  62. allocColor24_32(Color color)
  63. {
  64.     return (color.red)<<16 | (color.green)<<8 | color.blue;
  65. }
  66.  
  67. static long
  68. allocColor8(Color color)
  69. {
  70.     return cmp8[(color.red>>6)<<4 | (color.green>>6)<<2 | (color.blue>>6)];
  71. }
  72.  
  73. // Try to build a 4x4x4 colormap cube
  74. static void
  75. makeCmp8(Display *dpy, Colormap cmap)
  76. {
  77.     XColor color;
  78.     XColor colors[256];
  79.     long r,g,b;
  80.     int c;
  81.  
  82.     for(c=0; c < 256; c++) colors[c].pixel = c;
  83.     XQueryColors(dpy,cmap,colors,256);
  84.  
  85.     for (r=0; r < 4 ; r++) {
  86.         for (g=0; g < 4 ; g++) {
  87.             for (b=0; b < 4 ; b++) {
  88.                 color.flags = DoRed|DoGreen|DoBlue;
  89.                 color.pad = 0;
  90.                 color.red = r<<14;
  91.                 color.green = g<<14;
  92.                 color.blue = b<<14;
  93.                 if (XAllocColor(dpy,cmap,&color)) {
  94.                     cmp8[(r<<4)|(g<<2)|b] = color.pixel;
  95.                 } else {
  96.                     // Look to the first 'matching' color
  97.                     for (c = 0; c < 256; c++) {
  98.                         if (
  99.                             (color.red == (colors[c].red & 0xc000))
  100.                             &&
  101.                             (color.green == (colors[c].green & 0xc000))
  102.                             &&
  103.                             (color.blue == (colors[c].blue & 0xc000))
  104.                         ) {
  105.                             cmp8[(r<<4)|(g<<2)|b] = colors[c].pixel;
  106.                             break;
  107.                         }
  108.                     }
  109.                     /*
  110.                     if (c == 256)
  111.                         printf("Can't alloc color %d/%d/%d\n", r,g,b);
  112.                     */
  113.                 }
  114.             }
  115.         }
  116.     }
  117. }
  118.  
  119. // Public
  120.  
  121. GraphicDevice::GraphicDevice(Display *d, Window w)
  122. {
  123.     XWindowAttributes wattr;
  124.     XPixmapFormatValues *pf;
  125.     Visual *visual;
  126.     int nItems;
  127.     int n;
  128.     struct shmid_ds buf;
  129.  
  130.     dpy = d;
  131.     target = w;
  132.  
  133.     // Get Window dimension
  134.     XGetWindowAttributes(dpy, target, &wattr);
  135.  
  136.     // Get first visual, don't care about others, really !
  137.     visual = wattr.visual;
  138.  
  139. #if PRINT
  140.     printf("BitmapPad  = %d\n", BitmapPad(dpy));
  141.     printf("BitmapUnit = %d\n", BitmapUnit(dpy));
  142.     printf("Depth      = %d\n", DefaultDepth(dpy,DefaultScreen(dpy)));
  143.     printf("RedMask    = %x\n", visual->red_mask);
  144.     printf("GreenMask  = %x\n", visual->green_mask);
  145.     printf("BlueMask   = %x\n", visual->blue_mask);
  146.     printf("Bits/RGB   = %d\n", visual->bits_per_rgb);
  147. #endif
  148.  
  149.     redMask = visual->red_mask;
  150.     greenMask = visual->green_mask;
  151.     blueMask = visual->blue_mask;
  152.  
  153.     // Get screen info
  154.  
  155.     for(pf=XListPixmapFormats(dpy, &n); n--; pf++) {
  156.         if (pf->depth == DefaultDepth(dpy, DefaultScreen(dpy))) {
  157.             bpp = pf->bits_per_pixel/8;
  158.             pad = pf->scanline_pad/8;
  159.         }
  160. #if PRINT
  161.         printf("----------------\n");
  162.         printf("Depth          = %d\n", pf->depth);
  163.         printf("Bits Per Pixel = %d\n", pf->bits_per_pixel);
  164.         printf("Scanline Pad   = %d\n", pf->scanline_pad);
  165. #endif
  166.     }
  167.  
  168.     gc = DefaultGC(dpy, DefaultScreen(dpy));
  169.  
  170.     targetWidth = wattr.width;
  171.     targetHeight = wattr.height;
  172.  
  173. #if PRINT
  174.     printf("Target Width  = %d\n", targetWidth);
  175.     printf("Target Height = %d\n", targetHeight);
  176. #endif
  177.  
  178.     zoom = 20;
  179.     movieWidth = targetWidth;
  180.     movieHeight = targetHeight;
  181.  
  182.     if (bpp) {
  183.         bpl = (targetWidth*bpp + pad-1)/pad*pad;
  184.     } else {
  185.         bpl = (targetWidth/8 + pad-1)/pad*pad;
  186.     }
  187.  
  188.     switch (bpp) {
  189.         case 1:
  190.             makeCmp8(dpy, wattr.colormap);
  191.             allocColor = allocColor8;
  192.             redMask = 0xe0;
  193.             greenMask = 0x18;
  194.             blueMask = 0x07;
  195.             break;
  196.         case 2:
  197.             if (DefaultDepth(dpy, DefaultScreen(dpy)) == 16) {
  198.                 allocColor = allocColor16_565;
  199.             } else
  200.             if (DefaultDepth(dpy, DefaultScreen(dpy)) == 15) {
  201.                 allocColor = allocColor15;
  202.             }
  203.             break;
  204.         case 3:
  205.         case 4:
  206.             allocColor = allocColor24_32;
  207.             break;
  208.     }
  209.  
  210.     XSelectInput(dpy, target, ExposureMask|ButtonReleaseMask|ButtonPressMask|PointerMotionMask);
  211.  
  212.     // Prepare data for Direct Graphics
  213.     segInfo.readOnly = False;
  214.     segInfo.shmid = shmget (IPC_PRIVATE,targetHeight*bpl,IPC_CREAT|0777);
  215.     if (segInfo.shmid <0) {
  216.         perror("shmget");
  217.         fprintf(stderr,"Size = %d x %d\n", targetWidth, targetHeight);
  218.     }
  219.     segInfo.shmaddr = (char*)shmat (segInfo.shmid, 0, 0);
  220.     if ((long)segInfo.shmaddr == -1) {
  221.         perror("shmat");
  222.     }
  223.     XShmAttach(dpy, &segInfo);
  224. #ifdef linux
  225.     // Warning : this does NOT work properly on Solaris
  226.     // Special Linux shm behaviour is used here
  227.     // When number of attached clients falls down to zero
  228.     // the shm is removed. This is convenient when it crashes.
  229.     if (shmctl(segInfo.shmid, IPC_RMID, &buf) < 0) {
  230.         perror("shmctl");
  231.     }
  232. #endif
  233.     XSync(dpy, False);
  234.  
  235.     canvasBuffer = (char*)segInfo.shmaddr;
  236.  
  237.     canvas = XShmCreatePixmap(dpy,target,segInfo.shmaddr,&segInfo,targetWidth,targetHeight,DefaultDepth(dpy, DefaultScreen(dpy)));
  238.     XSync(dpy, False);
  239.  
  240.     buttonCursor = XCreateFontCursor(dpy, XC_hand2);
  241.     XFlush(dpy);
  242.  
  243.     handCursorActive = 0;
  244.  
  245.     hitTest = (unsigned char *)malloc(targetWidth*targetHeight);
  246.     resetHitTest();
  247.  
  248.     adjust = new Matrix;
  249.  
  250.     foregroundColor.red = 0;
  251.     foregroundColor.green = 0;
  252.     foregroundColor.blue = 0;
  253.  
  254.     backgroundColor.red = 0;
  255.     backgroundColor.green = 0;
  256.     backgroundColor.blue = 0;
  257.  
  258.     showMore = 0;
  259. }
  260.  
  261. GraphicDevice::~GraphicDevice()
  262. {
  263.     XShmDetach(dpy, &segInfo);
  264.     XSync(dpy,False);
  265.     XFreePixmap(dpy, canvas);
  266.     shmdt(segInfo.shmaddr);
  267.  
  268. #ifndef linux
  269.     struct shmid_ds buf;
  270.     if (shmctl(segInfo.shmid, IPC_RMID, &buf) < 0) {
  271.         perror("shmctl");
  272.     }
  273. #endif
  274.  
  275.     free(hitTest);
  276.  
  277.     if (adjust) {
  278.         delete adjust;
  279.     }
  280. }
  281.  
  282. ///////////// PLATFORM INDEPENDENT
  283. void
  284. GraphicDevice::resetHitTest()
  285. {
  286.     long id;
  287.  
  288.     for(id=0;id<256; id++)
  289.     {
  290.         hitTestLookUp[id] = 0;
  291.     }
  292.     memset(hitTest,0,targetWidth*targetHeight);
  293.     setHandCursor(0);
  294. }
  295.  
  296. ///////////// PLATFORM INDEPENDENT
  297. void
  298. GraphicDevice::clearHitTest(long tagId)
  299. {
  300.     long id;
  301.  
  302.     for (id=1; id<256; id++)
  303.     {
  304.         if (tagId == hitTestLookUp[id]) {
  305.             long n;
  306.  
  307.             hitTestLookUp[id] = 0;
  308.  
  309.             // Clear every ref to h in hitTest
  310.             for(n=0; n < targetWidth*targetHeight; n++)
  311.             {
  312.                 if (hitTest[n] == id) hitTest[n] = 0;
  313.             }
  314.             break;
  315.         }
  316.     }
  317. }
  318.  
  319. ///////////// PLATFORM INDEPENDENT
  320. unsigned char
  321. GraphicDevice::registerHitTest(long tagId)
  322. {
  323.     long id;
  324.     long reg=0;
  325.  
  326.     for (id=1; id<256; id++)
  327.     {
  328.         // If already registred give up
  329.         if (hitTestLookUp[id] == tagId) return 0;
  330.         // Remember a free id
  331.         if (reg == 0 && hitTestLookUp[id] == 0) reg = id;
  332.     }
  333.     // If id found then register
  334.     if (reg) {
  335.         hitTestLookUp[reg] = tagId;
  336.     }
  337.     return reg;
  338. }
  339.  
  340. ///////////// PLATFORM INDEPENDENT
  341. long
  342. GraphicDevice::checkHitTest(long tagId, long x, long y)
  343. {
  344.     long id;
  345.     
  346.     if (x<0 || x >= targetWidth || y < 0 || y >= targetHeight) return 0;
  347.  
  348.     for (id=1; id<256; id++)
  349.     {
  350.         if (hitTestLookUp[id] == tagId) {
  351.             if (hitTest[x+y*targetWidth] == id) {
  352.                 return 1;
  353.             }
  354.         }
  355.     }
  356.     return 0;
  357. }
  358.  
  359. ///////////// PLATFORM INDEPENDENT
  360. Color *
  361. GraphicDevice::getColormap(Color *old, long n, Cxform *cxform)
  362. {
  363.     Color *newCmp;
  364.  
  365.     newCmp = new Color[n];
  366.  
  367.     if (cxform) {
  368.         for(long i = 0; i < n; i++)
  369.         {
  370.             newCmp[i] = cxform->getColor(old[i]);
  371.             newCmp[i].pixel = allocColor(newCmp[i]);
  372.         }
  373.     } else {
  374.         for(long i = 0; i < n; i++)
  375.         {
  376.             newCmp[i].pixel = allocColor(old[i]);
  377.         }
  378.     }
  379.  
  380.     return newCmp;
  381. }
  382.  
  383. ///////////// PLATFORM INDEPENDENT
  384. SwfPix *
  385. GraphicDevice::createSwfPix(long width, long height)
  386. {
  387.     SwfPix *pix;
  388.  
  389.     pix = new SwfPix;
  390.  
  391.     pix->width = width;
  392.     pix->height = height;
  393.  
  394.     pix->data = (char*)malloc(width*height*bpp);
  395.  
  396.     pix->bpl = width*bpp;
  397.  
  398.     return pix;
  399. }
  400.  
  401. ///////////// PLATFORM INDEPENDENT
  402. void
  403. GraphicDevice::destroySwfPix(SwfPix *pix)
  404. {
  405.     free(pix->data);
  406.     delete pix;
  407. }
  408.  
  409. ///////////// PLATFORM INDEPENDENT
  410. long
  411. GraphicDevice::getHeight()
  412. {
  413.     return targetHeight;
  414. }
  415.  
  416. ///////////// PLATFORM INDEPENDENT
  417. long
  418. GraphicDevice::getWidth()
  419. {
  420.     return targetWidth;
  421. }
  422.  
  423. ///////////// PLATFORM INDEPENDENT
  424. Color
  425. GraphicDevice::getForegroundColor()
  426. {
  427.     return foregroundColor;
  428. }
  429.  
  430. void
  431. GraphicDevice::setForegroundColor(Color color)
  432. {
  433.     foregroundColor = color;
  434.     XSetForeground(dpy,gc,allocColor(color));
  435. }
  436.  
  437. ///////////// PLATFORM INDEPENDENT
  438. Color
  439. GraphicDevice::getBackgroundColor()
  440. {
  441.     return backgroundColor;
  442. }
  443.  
  444. ///////////// PLATFORM INDEPENDENT
  445. void
  446. GraphicDevice::setBackgroundColor(Color color)
  447. {
  448.     backgroundColor = color;
  449. }
  450.  
  451. ///////////// PLATFORM INDEPENDENT
  452. void
  453. GraphicDevice::setMovieDimension(long width, long height)
  454. {
  455.     float xAdjust, yAdjust;
  456.  
  457.     movieWidth = width;
  458.     movieHeight = height;
  459.  
  460.     xAdjust = (float)targetWidth*zoom/(float)width;
  461.     yAdjust = (float)targetHeight*zoom/(float)height;
  462.  
  463.     if (xAdjust < yAdjust) {
  464.         adjust->a = xAdjust;
  465.         adjust->d = xAdjust;
  466.     } else {
  467.         adjust->a = yAdjust;
  468.         adjust->d = yAdjust;
  469.     }
  470. }
  471.  
  472. ///////////// PLATFORM INDEPENDENT
  473. void
  474. GraphicDevice::setMovieZoom(int z)
  475. {
  476.     z *= 20;
  477.     if (z <= 0 || z > 100) return;
  478.     zoom = z;
  479.     setMovieDimension(movieWidth,movieHeight);
  480.     resetHitTest();
  481. }
  482.  
  483. ///////////// PLATFORM INDEPENDENT
  484. void
  485. GraphicDevice::setMovieOffset(long x, long y)
  486. {
  487.     adjust->tx = -zoom*x;
  488.     adjust->ty = -zoom*y;
  489.     resetHitTest();
  490. }
  491.  
  492. void
  493. GraphicDevice::setHandCursor(int active)
  494. {
  495.      if (active && !handCursorActive) {
  496.         XDefineCursor(dpy, target, buttonCursor);
  497.         handCursorActive = 1;
  498.      } 
  499.      if (!active && handCursorActive) {
  500.         XUndefineCursor(dpy, target);
  501.         handCursorActive = 0;
  502.      }
  503. }
  504.  
  505. ///////////// PLATFORM INDEPENDENT
  506. void
  507. GraphicDevice::clearCanvas()
  508. {
  509.     unsigned long      pixel;
  510.     char         *line;
  511.     long          h, w;
  512.  
  513.     pixel = allocColor(backgroundColor);
  514.     line = canvasBuffer;
  515.  
  516.     if (bpp == 2) {
  517.         short *point;
  518.  
  519.         for (h=0; h < targetHeight; h++) {
  520.             w = targetWidth;
  521.             for(point = (short*)line; w-- ; point++) {
  522.                 *point = (short)pixel;
  523.             }
  524.             line += bpl;
  525.         }
  526.     } else
  527.     if (bpp == 4) {
  528.         long *point;
  529.  
  530.         for (h=0; h < targetHeight; h++) {
  531.             w = targetWidth;
  532.             for(point = (long*)line; w-- ; point++) {
  533.                 *point = (long)pixel;
  534.             }
  535.             line += bpl;
  536.         }
  537.     } else
  538.     if (bpp == 1) {
  539.         char *point;
  540.  
  541.         for (h=0; h < targetHeight; h++) {
  542.             w = targetWidth;
  543.             for(point = (char*)line; w-- ; point++) {
  544.                 *point = (char)pixel;
  545.             }
  546.             line += bpl;
  547.         }
  548.     }
  549. }
  550.  
  551. void
  552. GraphicDevice::displayCanvas()
  553. {
  554.     XSetFunction(dpy,gc,GXcopy);
  555.     XCopyArea(dpy,canvas,target,gc,0,0,targetWidth,targetHeight,0,0);
  556.     XFlush(dpy);
  557. }
  558.  
  559. ///////////// PLATFORM INDEPENDENT
  560. long
  561. GraphicDevice::clip(long &y, long &start, long &end)
  562. {
  563.     if (y<0) return 1;
  564.     if (y>(targetHeight-1)) return 1;
  565.     if (end < start) {
  566.         long tmp;
  567.         tmp = end;
  568.         end = start;
  569.         start = tmp;
  570.     }
  571.     if (end < 0) return 1;
  572.     if (start < 0) start = 0;
  573.     else
  574.     if (start > (targetWidth-1)*20) return 1;
  575.     if (end > (targetWidth-1)*20) end = (targetWidth-1)*20;
  576.     return 0;
  577. }
  578.  
  579. // Mix two colors, this is anti-aliasing this is just
  580. // color balancing. Weight is between 0 and 20 (inclusive)
  581. // Closer to 0 means closer to c1, and, closer to 20 means
  582. // closer to c2.
  583.  
  584. ///////////// PLATFORM INDEPENDENT
  585. unsigned long
  586. GraphicDevice::mix(unsigned long c1, unsigned long c2, int weight)
  587. {
  588.     long r1,r2,r;
  589.     long g1,g2,g;
  590.     long b1,b2,b;
  591.  
  592.     r1 = c1 & redMask;
  593.     r2 = c2 & redMask;
  594.     g1 = c1 & greenMask;
  595.     g2 = c2 & greenMask;
  596.     b1 = c1 & blueMask;
  597.     b2 = c2 & blueMask;
  598.  
  599.     r = ((r2*weight + r1 * (20-weight))/20) & redMask;
  600.     g = ((g2*weight + g1 * (20-weight))/20) & greenMask;
  601.     b = ((b2*weight + b1 * (20-weight))/20) & blueMask;
  602.  
  603.     return (r|g|b);
  604. }
  605.  
  606. #define aaCore(TYPE) { \
  607.         TYPE *line;    \
  608.         TYPE *point;    \
  609.     \
  610.         line = (TYPE *)(canvasBuffer + bpl*y);    \
  611.         point = &line[start/20];    \
  612.         *point = (TYPE)mix(pixel, *point, start%20);    \
  613.     \
  614.         if (start/20 == end/20) return;    \
  615.     \
  616.         point = &line[end/20];    \
  617.         *point = (TYPE)mix(*point, pixel, end%20);    \
  618. }
  619.  
  620. ///////////// PLATFORM INDEPENDENT
  621. void
  622. GraphicDevice::aa(long pixel, long y, long start, long end)
  623. {
  624.     if (bpp == 2) {
  625.         aaCore(unsigned short);
  626.     } else
  627.     if (bpp == 4) {
  628.         aaCore(unsigned long);
  629.     }
  630. }
  631.  
  632. #define fillLineSolid(TYPE) {             \
  633.     TYPE *line;                \
  634.     TYPE *point;                \
  635.                         \
  636.     line = (TYPE *)(canvasBuffer + bpl*y);    \
  637.     point = &line[start];            \
  638.     n = end-start;                \
  639.     while (n--) {                \
  640.         *point = (TYPE)pixel;        \
  641.         point++;            \
  642.     }                    \
  643. }
  644.  
  645. ///////////// PLATFORM INDEPENDENT
  646. void
  647. GraphicDevice::fillLine(long pixel, long y, long start, long end, int doAa)
  648. {
  649.     register long   n;
  650.  
  651.     if (clip(y,start,end)) return;
  652.  
  653.     if (doAa) {
  654.         aa(pixel,y,start,end);
  655.  
  656.         start /= 20;
  657.         end /= 20;
  658.  
  659.         start++;
  660.         if (end <= start) return;
  661.     } else {
  662.         start /= 20;
  663.         end /= 20;
  664.     }
  665.  
  666.     if (bpp == 2) {
  667.         fillLineSolid(unsigned short);
  668.     } else
  669.     if (bpp == 4) {
  670.         fillLineSolid(unsigned long);
  671.     } else
  672.     if (bpp == 1) {
  673.         fillLineSolid(unsigned char);
  674.     }
  675. }
  676.  
  677. ///////////// PLATFORM INDEPENDENT
  678. void
  679. GraphicDevice::fillLine(SwfPix *pix, long xOffset, long yOffset, long y, long start, long end)
  680. {
  681.     char *lineDest, *lineSrc;
  682.  
  683.     if (pix == 0) return;
  684.     if (y-yOffset < 0) return;
  685.     if (y-yOffset >= pix->height) return;
  686.     if (clip(y,start,end)) return;
  687.  
  688.     start /= 20;
  689.     end /= 20;
  690.  
  691.     lineDest = canvasBuffer + bpl*y;
  692.     lineDest += start*bpp;
  693.  
  694.     if (end-start >= pix->width) {
  695.         end = start+pix->width-1;
  696.     }
  697.  
  698.     lineSrc = pix->data + pix->bpl*(y-yOffset);
  699.     if (start-xOffset < 0) return;
  700.     lineSrc += (start-xOffset)*bpp;
  701.  
  702.     memcpy(lineDest,lineSrc,bpp*(end-start));
  703. }
  704.  
  705. #define fillLineLinearGradient(TYPE) {             \
  706.     TYPE *line;                    \
  707.     TYPE *point;                    \
  708.                             \
  709.     line = (TYPE *)(canvasBuffer + bpl*y);        \
  710.     point = &line[start];                \
  711.                             \
  712.     while (n--) {                    \
  713.         *point = (TYPE)grad->ramp[r>>16].pixel;    \
  714.         point++;                \
  715.         r += dr;                \
  716.     }                        \
  717. }
  718.  
  719. ///////////// PLATFORM INDEPENDENT
  720. void
  721. GraphicDevice::fillLine(Gradient *grad, long y, long start, long end)
  722. {
  723.     long rampStart, rampEnd;
  724.     long dr,r;
  725.     register long   n;
  726.  
  727.     if (clip(y,start,end)) return;
  728.  
  729.     start /= 20;
  730.     end /= 20;
  731.  
  732.     n = end-start;
  733.  
  734.     rampStart = (grad->imat.getX(start*20-grad->xOffset,y*20-grad->yOffset)+16384)/128;
  735.     rampEnd   = (grad->imat.getX(end*20-grad->xOffset,y*20-grad->yOffset)+16384)/128;
  736.  
  737.     if (rampStart < 0) {
  738.         rampStart = 0;
  739.     } else
  740.     if (rampStart > 255) {
  741.         rampStart = 255;
  742.     }
  743.  
  744.     if (rampEnd < 0) {
  745.         rampEnd = 0;
  746.     } else
  747.     if (rampEnd > 255) {
  748.         rampEnd = 255;
  749.     }
  750.  
  751.     dr = ((rampEnd-rampStart)<<16)/(n+1);
  752.     r = rampStart<<16;
  753.  
  754.     if (bpp == 2) {
  755.         fillLineLinearGradient(unsigned short);
  756.     } else
  757.     if (bpp == 4) {
  758.         fillLineLinearGradient(unsigned long);
  759.     } else
  760.     if (bpp == 1) {
  761.         fillLineLinearGradient(unsigned char);
  762.     }
  763. }
  764.  
  765. #define fillLineRadialGradient(TYPE) {                     \
  766.     TYPE *line;                            \
  767.     TYPE *point;                            \
  768.                                     \
  769.     line = (TYPE *)(canvasBuffer + bpl*y);                \
  770.     point = &line[start];                        \
  771.                                     \
  772.     while (n--) {                            \
  773.         dist2 = ((X>>16)*(X>>16))+((Y>>16)*(Y>>16));        \
  774.         if (dist2 > 65536) {                    \
  775.             r = 255;                    \
  776.         } else {                        \
  777.             r= SQRT[((X>>16)*(X>>16))+((Y>>16)*(Y>>16))];    \
  778.         }                            \
  779.         *point = (TYPE)grad->ramp[r].pixel;            \
  780.         point++;                        \
  781.         X += dx;                        \
  782.         Y += dy;                        \
  783.     }                                \
  784. }
  785.  
  786. ///////////// PLATFORM INDEPENDENT
  787. void
  788. GraphicDevice::fillLineRG(Gradient *grad, long y, long start, long end)
  789. {
  790.     long rampStartx, rampEndx, rampStarty, rampEndy;
  791.     long X,dx,r,Y,dy;
  792.     long dist2;
  793.     register long   n;
  794.  
  795.     if (clip(y,start,end)) return;
  796.  
  797.     start /= 20;
  798.     end /= 20;
  799.  
  800.     n = end-start;
  801.  
  802.     rampStartx = (grad->imat.getX(start*20-grad->xOffset,y*20-grad->yOffset))/64;
  803.     rampStarty = (grad->imat.getY(start*20-grad->xOffset,y*20-grad->yOffset))/64;
  804.     rampEndx   = (grad->imat.getX(end*20-grad->xOffset,y*20-grad->yOffset))/64;
  805.     rampEndy   = (grad->imat.getY(end*20-grad->xOffset,y*20-grad->yOffset))/64;
  806.  
  807.     dx = ((rampEndx-rampStartx)<<16)/(n+1);
  808.     X = rampStartx<<16;
  809.     dy = ((rampEndy-rampStarty)<<16)/(n+1);
  810.     Y = rampStarty<<16;
  811.  
  812.     if (bpp == 2) {
  813.         fillLineRadialGradient(unsigned short);
  814.     } else
  815.     if (bpp == 4) {
  816.         fillLineRadialGradient(unsigned long);
  817.     } else
  818.     if (bpp == 1) {
  819.         fillLineRadialGradient(unsigned char);
  820.     }
  821. }
  822.  
  823. ///////////// PLATFORM INDEPENDENT
  824. void
  825. GraphicDevice::fillHitTestLine(unsigned char id, long y, long start, long end)
  826. {
  827.     unsigned char *ptr;
  828.     long n;
  829.  
  830.     if (clip(y,start,end)) return;
  831.  
  832.     start /= 20;
  833.     end /= 20;
  834.  
  835.     ptr = &hitTest[y*targetWidth + start];
  836.  
  837.     n = end-start;
  838.     while (n--) {
  839.         *ptr = id;
  840.         ptr++;
  841.     }
  842. }
  843.  
  844. void
  845. GraphicDevice::drawLine(long x1, long y1, long x2, long y2, long width)
  846. {
  847.     static long w = -1;
  848.  
  849.     if (w != width) {
  850.         XSetLineAttributes(dpy, gc, ZOOM(width, 20), LineSolid, CapRound, JoinRound);
  851.         w = width;
  852.     }
  853.     XDrawLine(dpy,canvas,gc,ZOOM(x1,20),ZOOM(y1,20),ZOOM(x2,20),ZOOM(y2,20));
  854. }
  855.  
  856. void
  857. GraphicDevice::synchronize()
  858. {
  859.     XSync(dpy,False);
  860. }
  861.